﻿namespace UCSD_BioLit
{
    #region Namespace

    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Text.RegularExpressions;
    using Microsoft.Office.Core;
    using UCSD_BioLit.Properties;
    using MSWord = Microsoft.Office.Interop.Word;

    #endregion

    /// <summary>
    /// This class handles Uniprot term recognition and creation of NCBI mark-up buttons for the Word context menu.
    /// </summary>
    public class UniprotTerm : OntologyTermBase
    {
        /// <summary>
        /// Class name for exception title.
        /// </summary>
        private const string ExceptionString = "UniprotTerm";

        /// <summary>
        /// The Uniprot type text.
        /// </summary>
        private const string UniprotTypeValue = "Uniprot";

        /// <summary>
        /// Instance of the class UniprotTerm.
        /// </summary>
        private static UniprotTerm _uniprotTerm;

        /// <summary>
        /// Prevents a default instance of the UniprotTerm class from being created.
        /// </summary>
        private UniprotTerm()
            : base()
        {
        }

        /// <summary>
        /// Gets an Instance of the class UniprotTerm.
        /// </summary>
        /// <returns>The UniprotTerm instance.</returns>
        public static UniprotTerm Instance()
        {
            if (_uniprotTerm == null)
            {
                _uniprotTerm = new UniprotTerm();
            }

            return _uniprotTerm;
        }

        /// <summary>
        /// Overridden Recognize method to recognize Uniprot Terms.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">TermRecognitionEventArgs object with details about the current selection and cursor position.</param>
        public override void Recognize(object sender, TermRecognitionEventArgs e)
        {
            if (e != null)
            {
                string selectedText = e.SelectedText.Trim();

                // Expressions to search for Uniprot terms.
                string[] regularExpressions = new string[]
                {
                    @"\s[A-Z]{1}[0-9][a-zA-Z][0-9a-zA-Z]{2}[0-9]",
                    @"\s[A|O|P|Q]{1}[0-9][0-9a-zA-Z]{3}[0-9]"
                };

                this._termCollection.Clear();

                if (!String.IsNullOrEmpty(selectedText))
                {
                    foreach (var expression in regularExpressions)
                    {
                        Regex r = new Regex(expression);
                        Match m = r.Match(selectedText);
                        while (m.Success)
                        {
                            MSWord.Range range = e.SelectionRange.Duplicate;

                            // Check if the term has already been added to the list.
                            if (!this.TermCollection.Values.Any(delegate(RecognizedTermProperties props)
                            {
                                return String.Compare(props.RecognizedTerm.Trim(), m.Value.Trim(), true) == 0;
                            }))
                            {
                                // Find the range of all occurances of the terms near the current cursor position and add them to the list.
                                AddTermsInRange(range, m.Value, e.CursorPosition, e.IsSelection);
                            }

                            m = m.NextMatch();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Overridden CreateControls method to create Uniprot mark-up controls on the Word context menus.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The EventArgs.</param>
        public override void CreateControls(object sender, EventArgs e)
        {
            if (TermCollection.Count > 0)
            {
                foreach (string contextMenuName in ContextMenuHelper.OntologyContextMenus)
                {
                    CommandBar contextMenu = Globals.ThisAddIn.Application.CommandBars[contextMenuName.ToString()];

                    if (contextMenu != null)
                    {
                        // Find the "Ontology - Mark-up Selection" popup control which has already been added to the context menu.
                        CommandBarPopup popupControl = (CommandBarPopup)contextMenu.FindControl(
                            MsoControlType.msoControlPopup, Type.Missing, ContextMenuHelper.ContextMenuTag, true, true);

                        this.AddUniprotControl(popupControl, contextMenu.Id.ToString());
                    }
                }
            }
        }

        /// <summary>
        /// Adds the recognized Uniprot mark-up control.
        /// </summary>
        /// <param name="popupControl">The Popup control to add the Uniprot mark-up button to.</param>
        /// <param name="contextMenuId">The ID of the Word context menu to which the control is being added.</param>
        private void AddUniprotControl(CommandBarPopup popupControl, string contextMenuId)
        {
            foreach (var term in TermCollection)
            {
                try
                {
                    // Add the Popup control to which the mark-up options will be added.
                    CommandBarPopup ontologyPopup = (CommandBarPopup)popupControl.Controls.Add(
                                    MsoControlType.msoControlPopup, System.Type.Missing, System.Type.Missing, System.Type.Missing, true);
                    ontologyPopup.Caption = term.Value.RecognizedTerm;

                    // Add button for Uniprot Mark-up.
                    CommandBarButton buttonControl = (CommandBarButton)ontologyPopup.Controls.Add(
                                MsoControlType.msoControlButton, System.Type.Missing, System.Type.Missing, System.Type.Missing, true);

                    buttonControl.Caption = Resources.ADD_UNIPROT_STRING;
                    buttonControl.Tag = term.Key + Separator + contextMenuId;
                    buttonControl.Click += this.OnUniprotButtonClick;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message, ExceptionString);
                }
            }
        }

        /// <summary>
        /// Invoked when user clicks on the Uniprot Mark-up button.
        /// </summary>
        /// <param name="ctrl">The control which invoked this event.</param>
        /// <param name="cancelDefault">
        /// False if the default behavior associated with the CommandBarButton control occurs, 
        /// unless it’s canceled by another process or add-in.
        /// </param>
        private void OnUniprotButtonClick(CommandBarButton ctrl, ref bool cancelDefault)
        {
            // Get the Id from the control tag.
            string[] parms = ctrl.Tag.Split(new string[] { Separator }, StringSplitOptions.None);

            try
            {
                if (parms != null && parms.Length == 2)
                {
                    RecognizedTermProperties properties = this.TermCollection[parms[0]];

                    WordCommonFuncs.DBMarkup(properties.TermRange, properties.TermRange.Text, UniprotTypeValue, null);
                }
            }
            finally
            {
                ContextMenuHelper.Instance().ClearBiolitMenus();
            }
        }
    }
}
